/************************************
*  Copyright (C) 2010 Julien MOTTIN.
*  Contact: julien.mottin@gueydan.eu
*
*  This file is part of Gueydan.
*
*  Gueydan is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  Gueydan is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with Gueydan.  If not, see <http://www.gnu.org/licenses/>.
*
*************************************/
// Local
#include "fermentable.h"
#include "xmldico.h"

// QtCore
#include <QtGlobal>

// QtXml
#include <QDomNode>
#include <QDomElement>
#include <QDomDocument>
#include <QDomNodeList>
#include <QDomText>

Fermentable::Fermentable(const QString &iName,
                         const int iVersion,
                         const FermentableType iType,
                         const Weight &iAmount,
                         const float iYield,
                         const Color &iColor)
:BeerXMLObject(iName,iVersion)
,_Type(iType)
,_Amount(iAmount)
,_Yield(iYield)
,_Color(iColor)
,_AddAfterBoil(false)
,_Origin()
,_Supplier()
,_Notes()
,_CoarseFineDiff(0.0)
,_Moisture(0.0)
,_DiastaticPower(0.0)
,_Protein(0.0)
,_MaxInBatch(0.0)
,_RecommendMash(false)
,_IBUGalPerLB(0.0)
{
}

Fermentable::Fermentable()
:BeerXMLObject()
,_Type(FTGrain)
,_Amount(0)
,_Yield(0.0)
,_Color(0)
,_AddAfterBoil(false)
,_Origin()
,_Supplier()
,_Notes()
,_CoarseFineDiff(0.0)
,_Moisture(0.0)
,_DiastaticPower(0.0)
,_Protein(0.0)
,_MaxInBatch(0.0)
,_RecommendMash(false)
,_IBUGalPerLB(0.0)
{
}

Fermentable::~Fermentable()
{
}

bool Fermentable::operator==(const Fermentable &iOther) const
{
    return ((*this).BeerXMLObject::operator==(iOther) &&
            _Type == iOther._Type &&
            _Amount == iOther._Amount &&
            _Yield == iOther._Yield &&
            _Color == iOther._Color &&
            _AddAfterBoil == iOther._AddAfterBoil &&
            _Origin == iOther._Origin &&
            _Supplier == iOther._Supplier &&
            _Notes == iOther._Notes &&
            _CoarseFineDiff == iOther._CoarseFineDiff &&
            _Moisture == iOther._Moisture &&
            _DiastaticPower == iOther._DiastaticPower &&
            _Protein == iOther._Protein &&
            _MaxInBatch == iOther._MaxInBatch &&
            _RecommendMash == iOther._RecommendMash &&
            _IBUGalPerLB == iOther._IBUGalPerLB);
}

bool Fermentable::operator!=(const Fermentable &iOther) const
{
    return (!((*this)==iOther));
}

int Fermentable::CreateFromXMLNode(const QDomNode &iNode)
{
    int oRC = 1;
    if (!iNode.isNull())
    {
        QDomElement FermElement;

        // Case Document : check if doc has only one Fermentable element
        if (iNode.isDocument())
        {
            QDomDocument FermDoc = iNode.toDocument();
            QDomNodeList FermList = FermDoc.elementsByTagName(FERMENTABLE);
            if (FermList.length()==1)
                FermElement = FermList.item(0).toElement();
        }
        // Default : cast to element
        else
            FermElement = iNode.toElement();

        // Check element consistency
        if (!FermElement.isNull() && FERMENTABLE==FermElement.tagName())
        {
            // Check existence of mandatory elements
            bool FermName = false;
            bool FermVersion = false;
            bool FermType = false;
            bool FermAmount = false;
            bool FermYield = false;
            bool FermColor = false;
            QDomNode node = FermElement.firstChild();
            while (!node.isNull())
            {
                if (node.isElement())
                {
                    QDomElement elem = node.toElement();
                    QString name = elem.tagName();
                    QString text = elem.text();
                    if (name==FERM_NAME)
                    {
                        _Name = text;
                        FermName = true;
                    }
                    else if (name==FERM_VERSION)
                    {
                        bool ok = false;
                        int v = text.toInt(&ok);
                        if (ok)
                        {
                            _Version = v;
                            FermVersion = true;
                        }
                    }
                    else if (name==FERM_TYPE)
                    {
                        QString type = text.toLower();
                        FermType = true;
                        if (type==FERM_TYPE_GRAIN.toLower())
                            _Type = FTGrain;
                        else if (type==FERM_TYPE_SUGAR.toLower())
                            _Type = FTSugar;
                        else if (type==FERM_TYPE_EXTRACT.toLower())
                            _Type = FTExtract;
                        else if (type==FERM_TYPE_DRYEXTRACT.toLower())
                            _Type = FTDryExtract;
                        else if (type==FERM_TYPE_ADJUNCT.toLower())
                            _Type = FTAdjunct;
                        else
                        {
                            // Unknown type!
                            FermType = false;
                            break;
                        }
                    }
                    else if (name==FERM_AMOUNT)
                    {
                        bool ok = false;
                        Weight tmpAmount;
                        tmpAmount.FromString(text,&ok);
                        if (ok)
                        {
                            _Amount = tmpAmount;
                            FermAmount = true;
                        }
                    }
                    else if (name==FERM_YIELD)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                        {
                            _Yield = v;
                            FermYield = true;
                        }
                    }
                    else if (name==FERM_COLOR)
                    {
                        bool ok = false;
                        Color tmpCol;
                        tmpCol.FromString(text,&ok);
                        if (ok)
                        {
                            _Color = tmpCol;
                            FermColor = true;
                        }
                    }
                    else if (name==FERM_ADDAFTERBOIL)
                    {
                        if (text.toLower()=="true")
                            _AddAfterBoil = true;
                    }
                    else if (name==FERM_ORIGIN)
                    {
                        _Origin = text;
                    }
                    else if (name==FERM_SUPPLIER)
                    {
                        _Supplier = text;
                    }
                    else if (name==FERM_NOTES)
                    {
                        _Notes = text;
                    }
                    else if (name==FERM_COARSEFINEDIFF)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _CoarseFineDiff = v;
                    }
                    else if (name==FERM_MOISTURE)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _Moisture = v;
                    }
                    else if (name==FERM_DIASTATICPOWER)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _DiastaticPower = v;
                    }
                    else if (name==FERM_PROTEIN)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _Protein = v;
                    }
                    else if (name==FERM_MAXINBATCH)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _MaxInBatch = v;
                    }
                    else if (name==FERM_RECOMMENDMASH)
                    {
                        if (text.toLower()=="true")
                            _RecommendMash = true;
                    }
                    else if (name==FERM_IBUGALPERLB)
                    {
                        bool ok = false;
                        float v = text.toFloat(&ok);
                        if (ok)
                            _IBUGalPerLB = v;
                    }
                }

                // Iterate
                node = node.nextSibling();
            }

            if (FermName && FermVersion && FermType && FermAmount && FermYield && FermColor)
            {
               // Success!
                oRC = 0;
            }
        }
    }

    return oRC;
}

int Fermentable::ToXMLNode(QDomNode &iParentNode) const
{
    int oRC = 1;

    // First, create valid element node
    QDomDocument doc = iParentNode.ownerDocument();
    QDomElement FermNode = doc.createElement(FERMENTABLE);
    if (!FermNode.isNull())
    {
        if (!_Name.isEmpty() && _Version>0 && _Yield>=0 && _Color>0)
        {
            QDomElement Node;
            QDomText Text;
            QString str;

            // Name
            Node = doc.createElement(FERM_NAME);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(_Name);
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // Version
            Node = doc.createElement(FERM_VERSION);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(QString::number(_Version));
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // Type
            switch (_Type)
            {
            case FTGrain:
                str = FERM_TYPE_GRAIN;
                break;
            case FTSugar:
                str = FERM_TYPE_SUGAR;
                break;
            case FTExtract:
                str = FERM_TYPE_EXTRACT;
                break;
            case FTDryExtract:
                str = FERM_TYPE_DRYEXTRACT;
                break;
            case FTAdjunct:
                str = FERM_TYPE_ADJUNCT;
                break;
            }
            Node = doc.createElement(FERM_TYPE);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(str);
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // Amount
            Node = doc.createElement(FERM_AMOUNT);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(QString::number(_Amount.Value(Kilogram)));
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // Yield
            Node = doc.createElement(FERM_YIELD);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(QString::number(_Yield));
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // Color
            Node = doc.createElement(FERM_COLOR);
            Q_ASSERT(!Node.isNull());
            Text = doc.createTextNode(QString::number(_Color.Value(SRM)));
            Q_ASSERT(!Text.isNull());
            Node.appendChild(Text);
            FermNode.appendChild(Node);

            // AddAfterBoil
            if (_AddAfterBoil)
            {
                Node = doc.createElement(FERM_ADDAFTERBOIL);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode("TRUE");
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // Origin
            if (!_Origin.isEmpty())
            {
                Node = doc.createElement(FERM_ORIGIN);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(_Origin);
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // Supplier
            if (!_Supplier.isEmpty())
            {
                Node = doc.createElement(FERM_SUPPLIER);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(_Supplier);
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // Notes
            if (!_Notes.isEmpty())
            {
                Node = doc.createElement(FERM_NOTES);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(_Notes);
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // CoarseFineDiff
            if (_CoarseFineDiff>0)
            {
                Node = doc.createElement(FERM_COARSEFINEDIFF);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_CoarseFineDiff));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // Moisture
            if (_Moisture>0)
            {
                Node = doc.createElement(FERM_MOISTURE);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_Moisture));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // DiastaticPower
            if (_DiastaticPower>0)
            {
                Node = doc.createElement(FERM_DIASTATICPOWER);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_DiastaticPower));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // Protein
            if (_Protein>0)
            {
                Node = doc.createElement(FERM_PROTEIN);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_Protein));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // MaxInBatch
            if (_MaxInBatch>0)
            {
                Node = doc.createElement(FERM_MAXINBATCH);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_MaxInBatch));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // RecommendMash
            if (_RecommendMash)
            {
                Node = doc.createElement(FERM_RECOMMENDMASH);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode("TRUE");
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

            // IBUGalPerLB
            if (_IBUGalPerLB>0)
            {
                Node = doc.createElement(FERM_IBUGALPERLB);
                Q_ASSERT(!Node.isNull());
                Text = doc.createTextNode(QString::number(_IBUGalPerLB));
                Q_ASSERT(!Text.isNull());
                Node.appendChild(Text);
                FermNode.appendChild(Node);
            }

           // Update output
           QDomNode zeNode = iParentNode.appendChild(FermNode);
           if (!zeNode.isNull())
               oRC = 0;
        }
    }

    return oRC;
}
